package com.monkeysonnet.b2dFluent;

import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;

public abstract class FixtureFactory<T extends FixtureFactory<?>>
{
	private static final FixtureDef _initialDef = new FixtureDef();
	
	protected FixtureDef _def;
	protected Object _userData;
	private boolean _managed;
	
	public FixtureFactory(boolean managed)
	{
		_managed = managed;
		_def = new FixtureDef();
	}
	
	@SuppressWarnings("unchecked")
	public T radius(float r)
	{
		_def.shape.setRadius(r);
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T density(float d)
	{		
		_def.density = d;
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T friction(float f)
	{		
		_def.friction = f;
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T restitution(float r)
	{		
		_def.restitution = r;
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T category(int cat)
	{
		_def.filter.categoryBits = (short)cat;
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T mask(int mask)
	{
		_def.filter.maskBits = (short)mask;
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T userData(Object d)
	{
		_userData = d;
		return (T)this;
	}
	
	@SuppressWarnings("unchecked")
	public T sensor(boolean isSensor)
	{		
		_def.isSensor = isSensor;
		return (T)this;
	}
	
	public Fixture create(Body b)
	{
		Fixture f = b.createFixture(_def);
		f.setUserData(_userData);	
		_userData = null; // not owned. Release immediately.
		
		if(_managed)
			free();
		else if(_def.shape != null)
		{
			_def.shape.dispose();
			_def.shape = null;
		}
		
		return f;		
	}
	
	void clear()
	{	
		_userData = null;
		_def.density = _initialDef.density;
		_def.filter.categoryBits = _initialDef.filter.categoryBits;
		_def.filter.groupIndex = _initialDef.filter.groupIndex;
		_def.filter.maskBits = _initialDef.filter.maskBits;
		_def.friction = _initialDef.friction;
		_def.isSensor = _initialDef.isSensor;
		_def.restitution = _initialDef.restitution;				
	}
	
	void dispose()
	{
		if(_def.shape != null)
		{
			_def.shape.dispose();
			_def.shape = null;
		}
	}
	
	public abstract void free();
}
